package com.jsits.v2x.common.util;

import com.esotericsoftware.reflectasm.MethodAccess;
import com.jsits.framework.core.exception.BusinessException;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

public class ObjUtil
{

	/*
	 * 获得指定包下的所有class
	 */
	public static <E> List<Class<E>> getClassList(List<String> packageList)
	{
		List<Class<E>> classList = new ArrayList<Class<E>>();

		for (String packageName : packageList)
		{
			List<Class<E>> list = ClassUtil.getClasses(packageName);

			classList.addAll(list);
		}

		return classList;
	}

	/*
	 * 快速反射调用方法此功能要比正常jdk的要块 功能：&功能说明
	 */
	public static Object invokeFast(String methodName, Object obj, Object... args)
	{
		MethodAccess invoker = getMethodAccess(obj.getClass());

		if (ArrayUtils.isEmpty(args))
		{
			return invoker.invoke(obj, methodName);
		}
		return invoker.invoke(obj, methodName, args);
	}

	private static final Map<Class<?>, MethodAccess> invokerMap = new HashMap<Class<?>, MethodAccess>();

	private static MethodAccess getMethodAccess(Class<?> klass)
	{
		MethodAccess invoker = invokerMap.get(klass);
		if (invoker == null)
		{
			invoker = MethodAccess.get(klass);

			invokerMap.put(klass, invoker);
		}
		return invoker;
	}

	private static Map<String, String> setterMap = new HashMap<String, String>();

	private static String getParamSetMethodName(String param)
	{
		String method = setterMap.get(param);

		if (method == null)
		{
			StringBuilder sb = new StringBuilder(50);
			sb.append("set").append((char) (param.charAt(0) - 32)).append(param.substring(1));
			method = sb.toString();

			setterMap.put(param, method);
		}
		return method;
	}

	private static Map<String, String> getterMap = new HashMap<String, String>();

	public static String getParamGetMethodName(String param)
	{
		String method = getterMap.get(param);

		if (method == null)
		{
			StringBuilder sb = new StringBuilder(50);
			sb.append("get").append((char) (param.charAt(0) - 32)).append(param.substring(1));
			method = sb.toString();

			getterMap.put(param, method);
		}
		return method;
	}

	public static void setParamValue(Object obj, String fieldName, String paramValue) throws SecurityException, NoSuchMethodException, NoSuchFieldException
	{
		setParamValue(obj, getField(obj.getClass(), fieldName), paramValue);
	}

	/*
	 * 递归查找获取私有属性
	 */
	private static Field getField(Class<?> clazz, String fieldName) throws NoSuchFieldException, SecurityException
	{
		getAllFeilds(clazz);

		return fieldMap.get(clazz).get(fieldName);
	}

	/*
	 * 支持 int/int[]/Integer/String/String[]/float/float[]/Float/double/double[]/Double/boolean/boolean[]/Boolean 
	 * 不支持基本数据类型的对象数组，例如：Integer[]、Float[]、Double[]、Boolean[]等
	 */
	public static void setParamValue(Object obj, Field field, String paramValue) throws SecurityException, NoSuchMethodException, NoSuchFieldException
	{
		Object value = null;

		String paramType = field.getType().getName();

		if (paramType.equals("java.lang.String"))
		{
			value = paramValue;
		} else
		{
			paramValue = StringUtils.trim(paramValue);
			if (StringUtils.isBlank(paramValue))
			{
				return;
			}
			if (paramType.equals("int") || paramType.equals("java.lang.Integer"))
			{
				try
				{
					value = Integer.parseInt(paramValue);
				} catch (Exception e)
				{
					value = 0;
				}
			} else if (paramType.equals("long") || paramType.equals("java.lang.Long"))
			{
				try
				{
					value = Long.parseLong(paramValue);
				} catch (Exception e)
				{
					value = (long) 0;
				}
			} else if (paramType.equals("float") || paramType.equals("java.lang.Float"))
			{
				try
				{
					value = Float.parseFloat(paramValue);
				} catch (Exception e)
				{
					value = (float) 0.0;
				}
			} else if (paramType.equals("double") || paramType.equals("java.lang.Double"))
			{
				try
				{
					value = Double.parseDouble(paramValue);
				} catch (Exception e)
				{
					value = (double) 0.0;
				}
			} else if (paramType.equals("boolean") || paramType.equals("java.lang.Boolean"))
			{
				value = Boolean.parseBoolean(paramValue);

			} else if (paramType.equals("[Ljava.lang.String;"))
			{
				value = ArrayUtil.tostrs(paramValue);

			} else if (paramType.equals("[I")) // int array
			{
				value = ArrayUtil.toInts(paramValue);

			} else if (paramType.equals("[Z")) // bool array
			{
				value = ArrayUtil.toBooleans(paramValue);

			} else if (paramType.equals("[F")) // float array
			{
				value = ArrayUtil.toFloats(paramValue);
			} else if (paramType.equals("[D")) // float Array
			{
				value = ArrayUtil.toDoubles(paramValue);
			}
		}

		if (value != null)
		{
			String paramName = field.getName();
			String method = ObjUtil.getParamSetMethodName(paramName);
			ObjUtil.invokeFast(method, obj, value);
		}
	}

	public static Object getParamValue(Object obj, String fieldName) throws BusinessException
	{
		try
		{
			String method = ObjUtil.getParamGetMethodName(fieldName);

			return ObjUtil.invokeFast(method, obj);
		} catch (Exception e)
		{
			throw new BusinessException("get parameter value failed", e);
		}
	}
	
	public static <T> T newInstance(Class<T> klass) throws BusinessException
	{
		try
		{
			return klass.newInstance();
		} catch (Exception e)
		{
			throw new BusinessException("new instance class failed", e);
		}
	}

	private static Map<Class<?>, Map<String, Field>> fieldMap = new HashMap<Class<?>, Map<String, Field>>();

	public static Collection<Field> getAllFeilds(Class<?> c)
	{
		Map<String, Field> map = fieldMap.get(c);
		if (map == null)
		{
			map = new HashMap<String, Field>();

			Class<?> newClass = c;

			while (!Object.class.equals(newClass))
			{
				for (Field field : newClass.getDeclaredFields())
				{
					map.put(field.getName(), field);
				}
				newClass = newClass.getSuperclass();
			}

			fieldMap.put(c, map);
		}

		return map.values();
	}

}